; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt -S -dfa-jump-threading %s | FileCheck %s

; These tests check that the DFA jump threading transformation is applied
; properly to two CFGs. It checks that blocks are cloned, branches are updated,
; and SSA form is restored.
define i32 @test1(i32 %num) {
; CHECK-LABEL: @test1(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    br label [[FOR_BODY:%.*]]
; CHECK:       for.body:
; CHECK-NEXT:    [[COUNT:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[INC:%.*]], [[FOR_INC:%.*]] ]
; CHECK-NEXT:    [[STATE:%.*]] = phi i32 [ 1, [[ENTRY]] ], [ undef, [[FOR_INC]] ]
; CHECK-NEXT:    switch i32 [[STATE]], label [[FOR_INC_JT1:%.*]] [
; CHECK-NEXT:    i32 1, label [[CASE1:%.*]]
; CHECK-NEXT:    i32 2, label [[CASE2:%.*]]
; CHECK-NEXT:    ]
; CHECK:       for.body.jt2:
; CHECK-NEXT:    [[COUNT_JT2:%.*]] = phi i32 [ [[INC_JT2:%.*]], [[FOR_INC_JT2:%.*]] ]
; CHECK-NEXT:    [[STATE_JT2:%.*]] = phi i32 [ [[STATE_NEXT_JT2:%.*]], [[FOR_INC_JT2]] ]
; CHECK-NEXT:    br label [[CASE2]]
; CHECK:       for.body.jt1:
; CHECK-NEXT:    [[COUNT_JT1:%.*]] = phi i32 [ [[INC_JT1:%.*]], [[FOR_INC_JT1]] ]
; CHECK-NEXT:    [[STATE_JT1:%.*]] = phi i32 [ [[STATE_NEXT_JT1:%.*]], [[FOR_INC_JT1]] ]
; CHECK-NEXT:    br label [[CASE1]]
; CHECK:       case1:
; CHECK-NEXT:    [[COUNT2:%.*]] = phi i32 [ [[COUNT_JT1]], [[FOR_BODY_JT1:%.*]] ], [ [[COUNT]], [[FOR_BODY]] ]
; CHECK-NEXT:    br label [[FOR_INC_JT2]]
; CHECK:       case2:
; CHECK-NEXT:    [[COUNT1:%.*]] = phi i32 [ [[COUNT_JT2]], [[FOR_BODY_JT2:%.*]] ], [ [[COUNT]], [[FOR_BODY]] ]
; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[COUNT1]], 50
; CHECK-NEXT:    br i1 [[CMP]], label [[FOR_INC_JT1]], label [[SI_UNFOLD_FALSE:%.*]]
; CHECK:       si.unfold.false:
; CHECK-NEXT:    br label [[FOR_INC_JT2]]
; CHECK:       for.inc:
; CHECK-NEXT:    [[INC]] = add nsw i32 undef, 1
; CHECK-NEXT:    [[CMP_EXIT:%.*]] = icmp slt i32 [[INC]], [[NUM:%.*]]
; CHECK-NEXT:    br i1 [[CMP_EXIT]], label [[FOR_BODY]], label [[FOR_END:%.*]]
; CHECK:       for.inc.jt2:
; CHECK-NEXT:    [[COUNT4:%.*]] = phi i32 [ [[COUNT1]], [[SI_UNFOLD_FALSE]] ], [ [[COUNT2]], [[CASE1]] ]
; CHECK-NEXT:    [[STATE_NEXT_JT2]] = phi i32 [ 2, [[CASE1]] ], [ 2, [[SI_UNFOLD_FALSE]] ]
; CHECK-NEXT:    [[INC_JT2]] = add nsw i32 [[COUNT4]], 1
; CHECK-NEXT:    [[CMP_EXIT_JT2:%.*]] = icmp slt i32 [[INC_JT2]], [[NUM]]
; CHECK-NEXT:    br i1 [[CMP_EXIT_JT2]], label [[FOR_BODY_JT2]], label [[FOR_END]]
; CHECK:       for.inc.jt1:
; CHECK-NEXT:    [[COUNT3:%.*]] = phi i32 [ [[COUNT1]], [[CASE2]] ], [ [[COUNT]], [[FOR_BODY]] ]
; CHECK-NEXT:    [[STATE_NEXT_JT1]] = phi i32 [ 1, [[CASE2]] ], [ 1, [[FOR_BODY]] ]
; CHECK-NEXT:    [[INC_JT1]] = add nsw i32 [[COUNT3]], 1
; CHECK-NEXT:    [[CMP_EXIT_JT1:%.*]] = icmp slt i32 [[INC_JT1]], [[NUM]]
; CHECK-NEXT:    br i1 [[CMP_EXIT_JT1]], label [[FOR_BODY_JT1]], label [[FOR_END]]
; CHECK:       for.end:
; CHECK-NEXT:    ret i32 0
;
entry:
  br label %for.body

for.body:
  %count = phi i32 [ 0, %entry ], [ %inc, %for.inc ]
  %state = phi i32 [ 1, %entry ], [ %state.next, %for.inc ]
  switch i32 %state, label %for.inc [
  i32 1, label %case1
  i32 2, label %case2
  ]

case1:
  br label %for.inc

case2:
  %cmp = icmp eq i32 %count, 50
  %sel = select i1 %cmp, i32 1, i32 2
  br label %for.inc

for.inc:
  %state.next = phi i32 [ %sel, %case2 ], [ 1, %for.body ], [ 2, %case1 ]
  %inc = add nsw i32 %count, 1
  %cmp.exit = icmp slt i32 %inc, %num
  br i1 %cmp.exit, label %for.body, label %for.end

for.end:
  ret i32 0
}


define i32 @test2(i32 %init) {
; CHECK-LABEL: @test2(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[INIT:%.*]], 0
; CHECK-NEXT:    br i1 [[CMP]], label [[LOOP_1:%.*]], label [[SI_UNFOLD_FALSE1:%.*]]
; CHECK:       si.unfold.false:
; CHECK-NEXT:    br label [[LOOP_1]]
; CHECK:       si.unfold.false.jt2:
; CHECK-NEXT:    br label [[LOOP_1_JT2:%.*]]
; CHECK:       si.unfold.false.jt4:
; CHECK-NEXT:    br label [[LOOP_1_JT4:%.*]]
; CHECK:       si.unfold.false1:
; CHECK-NEXT:    br label [[LOOP_1]]
; CHECK:       loop.1:
; CHECK-NEXT:    [[STATE_1:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ undef, [[SI_UNFOLD_FALSE:%.*]] ], [ 2, [[SI_UNFOLD_FALSE1]] ]
; CHECK-NEXT:    br label [[LOOP_2:%.*]]
; CHECK:       loop.1.jt2:
; CHECK-NEXT:    [[STATE_1_JT2:%.*]] = phi i32 [ [[STATE_1_BE_JT2:%.*]], [[SI_UNFOLD_FALSE_JT2:%.*]] ]
; CHECK-NEXT:    br label [[LOOP_2_JT2:%.*]]
; CHECK:       loop.1.jt4:
; CHECK-NEXT:    [[STATE_1_JT4:%.*]] = phi i32 [ [[STATE_1_BE_JT4:%.*]], [[SI_UNFOLD_FALSE_JT4:%.*]] ]
; CHECK-NEXT:    br label [[LOOP_2_JT4:%.*]]
; CHECK:       loop.1.jt1:
; CHECK-NEXT:    [[STATE_1_JT1:%.*]] = phi i32 [ 1, [[LOOP_1_BACKEDGE:%.*]] ], [ 1, [[LOOP_1_BACKEDGE_JT4:%.*]] ], [ 1, [[LOOP_1_BACKEDGE_JT2:%.*]] ]
; CHECK-NEXT:    br label [[LOOP_2_JT1:%.*]]
; CHECK:       loop.2:
; CHECK-NEXT:    [[STATE_2:%.*]] = phi i32 [ [[STATE_1]], [[LOOP_1]] ], [ undef, [[LOOP_2_BACKEDGE:%.*]] ]
; CHECK-NEXT:    br label [[LOOP_3:%.*]]
; CHECK:       loop.2.jt2:
; CHECK-NEXT:    [[STATE_2_JT2:%.*]] = phi i32 [ [[STATE_1_JT2]], [[LOOP_1_JT2]] ]
; CHECK-NEXT:    br label [[LOOP_3_JT2:%.*]]
; CHECK:       loop.2.jt3:
; CHECK-NEXT:    [[STATE_2_JT3:%.*]] = phi i32 [ [[STATE_2_BE_JT3:%.*]], [[LOOP_2_BACKEDGE_JT3:%.*]] ]
; CHECK-NEXT:    br label [[LOOP_3_JT3:%.*]]
; CHECK:       loop.2.jt0:
; CHECK-NEXT:    [[STATE_2_JT0:%.*]] = phi i32 [ [[STATE_2_BE_JT0:%.*]], [[LOOP_2_BACKEDGE_JT0:%.*]] ]
; CHECK-NEXT:    br label [[LOOP_3_JT0:%.*]]
; CHECK:       loop.2.jt4:
; CHECK-NEXT:    [[STATE_2_JT4:%.*]] = phi i32 [ [[STATE_1_JT4]], [[LOOP_1_JT4]] ]
; CHECK-NEXT:    br label [[LOOP_3_JT4:%.*]]
; CHECK:       loop.2.jt1:
; CHECK-NEXT:    [[STATE_2_JT1:%.*]] = phi i32 [ [[STATE_1_JT1]], [[LOOP_1_JT1:%.*]] ]
; CHECK-NEXT:    br label [[LOOP_3_JT1:%.*]]
; CHECK:       loop.3:
; CHECK-NEXT:    [[STATE:%.*]] = phi i32 [ [[STATE_2]], [[LOOP_2]] ]
; CHECK-NEXT:    switch i32 [[STATE]], label [[INFLOOP_I:%.*]] [
; CHECK-NEXT:    i32 2, label [[CASE2:%.*]]
; CHECK-NEXT:    i32 3, label [[CASE3:%.*]]
; CHECK-NEXT:    i32 4, label [[CASE4:%.*]]
; CHECK-NEXT:    i32 0, label [[CASE0:%.*]]
; CHECK-NEXT:    i32 1, label [[CASE1:%.*]]
; CHECK-NEXT:    ]
; CHECK:       loop.3.jt2:
; CHECK-NEXT:    [[STATE_JT2:%.*]] = phi i32 [ [[STATE_2_JT2]], [[LOOP_2_JT2]] ]
; CHECK-NEXT:    br label [[CASE2]]
; CHECK:       loop.3.jt0:
; CHECK-NEXT:    [[STATE_JT0:%.*]] = phi i32 [ [[STATE_2_JT0]], [[LOOP_2_JT0:%.*]] ]
; CHECK-NEXT:    br label [[CASE0]]
; CHECK:       loop.3.jt4:
; CHECK-NEXT:    [[STATE_JT4:%.*]] = phi i32 [ [[STATE_2_JT4]], [[LOOP_2_JT4]] ]
; CHECK-NEXT:    br label [[CASE4]]
; CHECK:       loop.3.jt1:
; CHECK-NEXT:    [[STATE_JT1:%.*]] = phi i32 [ [[STATE_2_JT1]], [[LOOP_2_JT1]] ]
; CHECK-NEXT:    br label [[CASE1]]
; CHECK:       loop.3.jt3:
; CHECK-NEXT:    [[STATE_JT3:%.*]] = phi i32 [ 3, [[CASE2]] ], [ [[STATE_2_JT3]], [[LOOP_2_JT3:%.*]] ]
; CHECK-NEXT:    br label [[CASE3]]
; CHECK:       case2:
; CHECK-NEXT:    br i1 [[CMP]], label [[LOOP_3_JT3]], label [[LOOP_1_BACKEDGE_JT4]]
; CHECK:       case3:
; CHECK-NEXT:    br i1 [[CMP]], label [[LOOP_2_BACKEDGE_JT0]], label [[CASE4]]
; CHECK:       case4:
; CHECK-NEXT:    br i1 [[CMP]], label [[LOOP_2_BACKEDGE_JT3]], label [[LOOP_1_BACKEDGE_JT2]]
; CHECK:       loop.1.backedge:
; CHECK-NEXT:    br i1 [[CMP]], label [[LOOP_1_JT1]], label [[SI_UNFOLD_FALSE]]
; CHECK:       loop.1.backedge.jt2:
; CHECK-NEXT:    [[STATE_1_BE_JT2]] = phi i32 [ 2, [[CASE4]] ]
; CHECK-NEXT:    br i1 [[CMP]], label [[LOOP_1_JT1]], label [[SI_UNFOLD_FALSE_JT2]]
; CHECK:       loop.1.backedge.jt4:
; CHECK-NEXT:    [[STATE_1_BE_JT4]] = phi i32 [ 4, [[CASE2]] ]
; CHECK-NEXT:    br i1 [[CMP]], label [[LOOP_1_JT1]], label [[SI_UNFOLD_FALSE_JT4]]
; CHECK:       loop.2.backedge:
; CHECK-NEXT:    br label [[LOOP_2]]
; CHECK:       loop.2.backedge.jt3:
; CHECK-NEXT:    [[STATE_2_BE_JT3]] = phi i32 [ 3, [[CASE4]] ]
; CHECK-NEXT:    br label [[LOOP_2_JT3]]
; CHECK:       loop.2.backedge.jt0:
; CHECK-NEXT:    [[STATE_2_BE_JT0]] = phi i32 [ 0, [[CASE3]] ]
; CHECK-NEXT:    br label [[LOOP_2_JT0]]
; CHECK:       case0:
; CHECK-NEXT:    br label [[EXIT:%.*]]
; CHECK:       case1:
; CHECK-NEXT:    br label [[EXIT]]
; CHECK:       infloop.i:
; CHECK-NEXT:    br label [[INFLOOP_I]]
; CHECK:       exit:
; CHECK-NEXT:    ret i32 0
;
entry:
  %cmp = icmp eq i32 %init, 0
  %sel = select i1 %cmp, i32 0, i32 2
  br label %loop.1

loop.1:
  %state.1 = phi i32 [ %sel, %entry ], [ %state.1.be2, %loop.1.backedge ]
  br label %loop.2

loop.2:
  %state.2 = phi i32 [ %state.1, %loop.1 ], [ %state.2.be, %loop.2.backedge ]
  br label %loop.3

loop.3:
  %state = phi i32 [ %state.2, %loop.2 ], [ 3, %case2 ]
  switch i32 %state, label %infloop.i [
  i32 2, label %case2
  i32 3, label %case3
  i32 4, label %case4
  i32 0, label %case0
  i32 1, label %case1
  ]

case2:
  br i1 %cmp, label %loop.3, label %loop.1.backedge

case3:
  br i1 %cmp, label %loop.2.backedge, label %case4

case4:
  br i1 %cmp, label %loop.2.backedge, label %loop.1.backedge

loop.1.backedge:
  %state.1.be = phi i32 [ 2, %case4 ], [ 4, %case2 ]
  %state.1.be2 = select i1 %cmp, i32 1, i32 %state.1.be
  br label %loop.1

loop.2.backedge:
  %state.2.be = phi i32 [ 3, %case4 ], [ 0, %case3 ]
  br label %loop.2

case0:
  br label %exit

case1:
  br label %exit

infloop.i:
  br label %infloop.i

exit:
  ret i32 0
}
